﻿/*
 * executor.cpp
 *
 *  Created on: 2017年6月18日
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_OS_PROTOCOL DM_API_EXPORT

#include <dm/os/protocol/executor.hpp>
#include <dm/os/log/logger.hpp>
#include <dm/os/protocol/telegram.hpp>

namespace dm{
namespace os{
namespace protocol{

static const char* logModule = "CExecutor.protocol.os.dm";

/**
 * 构造函数
 * 默认尝试连接延时10秒
 */
CExecutor::CExecutor():m_io(NULL),m_tryConnectDelay(10),m_protocol(NULL){
	log().debug(THISMODULE "创建对象");
}

/**
 * 析构函数
 */
CExecutor::~CExecutor(){
	log().debug(THISMODULE "销毁对象");
	if( m_io )
		delete m_io;

	if( m_protocol )
		delete m_protocol;
}

void CExecutor::setIo( io::CIo* io ){
	dm::CTimeStamp ts = dm::CTimeStamp::cur();
	dm::CRunTimeStamp rts = dm::CRunTimeStamp::cur();

	if( m_protocol ){
		if( m_io!=NULL ){
			if( m_io->isOpen() )
				m_protocol->onLinkClosed(ts,rts);
			delete m_io;
		}

		m_io = io;
		if( m_io->isOpen() )
			m_protocol->onLinkSettled(ts,rts);
	}else{
		if( m_io!=NULL )
			delete m_io;

		m_io = io;
	}
}

void CExecutor::setProtocol( dm::protocol::CProtocolBase* protocol ){
	if( m_protocol!=NULL )
		delete m_protocol;

	m_protocol = protocol;

	if( m_io && m_io->isOpen() && m_protocol ){
		m_protocol->onLinkSettled(dm::CTimeStamp::cur(),dm::CRunTimeStamp::cur());
		++m_connectTimes;
	}
}

bool CExecutor::isConnected()const{
	return m_io && m_io->isOpen();
}

bool CExecutor::tryConnect(){
	if( m_io && m_protocol && m_io->isOpenable() && !(m_io->isOpen()) ){
		if( m_lastTryConnect.isTimeout_sec(m_tryConnectDelay) ){
			m_lastTryConnect = dm::CRunTimeStamp::cur();
			++m_connectTimes;

			if( m_io->open() ){
				m_protocol->onLinkSettled(dm::CTimeStamp::cur(),m_lastTryConnect);
			}

			return true;
		}
	}

	return false;
}

void CExecutor::rx(){
	dm::CTimeStamp ts = dm::CTimeStamp::cur();
	dm::CRunTimeStamp rts = dm::CRunTimeStamp::cur();

	if( m_io && m_protocol && m_io->isOpen() ){
		dm::uint8 buf[2048];
		int len = m_io->read(buf,2048);
		if( len<0 ){
			m_protocol->onLinkClosed(ts,rts);
		}else{
			m_rxBuf.push(buf,len);
			telegram().pushRaw(m_protocol->name(),buf,len);

			while( true ){
				pos_t p = m_rxPos;
				if( m_protocol->getRxFrame().decode( m_rxBuf,m_rxBuf.getPos(),m_rxPos,&(m_protocol->getTxFrame()) ) ){
					if( !m_protocol->filterRxFrame() ){
						dm::uint8 tmp[3072];
						size_t l = m_rxPos - p;
						m_rxBuf.getDataAndMovePos(tmp,l,p);
						telegram().pushRx(m_protocol->name(),tmp,l);
						m_protocol->updateRecvTime(l,rts);

						switch( m_protocol->dealRxFrame(ts,rts) ){
						case protocol_t::Action_Nothing:
						case protocol_t::Action_ReTime:
							break;
						case protocol_t::Action_Send:
						case protocol_t::Action_SendAndReTime:
							m_protocol->getTxFrame().encode(m_txBuf);
							return;
							break;
						case protocol_t::Action_CloseLink:
							m_io->close();
							m_protocol->onLinkClosed(ts,rts);
							return;
						default:
							break;
						}
					}
				}else
					return;
			}
		}
	}
}

void CExecutor::tx(){
	dm::CTimeStamp ts = dm::CTimeStamp::cur();
	dm::CRunTimeStamp rts = dm::CRunTimeStamp::cur();

	if( m_txBuf.getLen()>0 && m_io->isOpen()){
		telegram().pushTx(m_protocol->name(),m_txBuf.getData(),m_txBuf.getLen());

		int p = 0;
		int s = 0;
		while( s>=0 ){
			p += s;
			if( (unsigned int)p>=m_txBuf.getLen() )
				break;
			s = m_io->write(m_txBuf.getData()+p,m_txBuf.getLen()-p);
		}

		m_protocol->updateSendTime(m_txBuf.getLen(),rts);
		m_txBuf.reset();
		if( !m_io->isOpen() )
			m_protocol->onLinkClosed(ts,rts);
	}

	if( m_txBuf.getLen()==0 ){
		// 发送缓冲区为空，可以发送数据

		switch( m_protocol->timedRefresh(ts,rts) ){
		case protocol_t::Action_Send:
		case protocol_t::Action_SendAndReTime:
			m_protocol->getTxFrame().encode(m_txBuf);
			break;
		case protocol_t::Action_CloseLink:
			log().info( THISMODULE "关闭连接");
			m_io->close();
			m_protocol->onLinkClosed(ts,rts);
			break;
		default:
			break;
		}
	}
}

}
}
}


